package com.katze.ssh.cmd;

import com.katze.ssh.IChannel;
import com.katze.ssh.SSHException;
import com.katze.ssh.SshSessionEntry;
import org.apache.sshd.client.channel.ChannelShell;
import org.apache.sshd.common.SshException;
import org.apache.sshd.common.channel.exception.SshChannelOpenException;
import org.apache.sshd.core.CoreModuleProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;
import java.util.function.Consumer;

public class ShellChannel implements IChannel{
    private static final Logger log = LoggerFactory.getLogger(ShellChannel.class);

    private final SshSessionEntry session;
    private final OutputStream outputStream;
    private final OutputStream errStream;
    private ChannelShell channel;
    private Charset charset = StandardCharsets.UTF_8;
    private Consumer<String> out;

    public ShellChannel(SshSessionEntry session) {
        this.session = session;
        this.outputStream = new PipedOutputStream() {
            @Override
            public void write(byte[] b, int off, int len) throws IOException {
                if (getOut() != null) {
                    getOut().accept(new String(b, off, len, getCharset()));
                }
            }
        };

        this.errStream = new PipedOutputStream() {
            @Override
            public void write(byte[] b, int off, int len) throws IOException {
                if (getOut() != null) {
                    getOut().accept("\u001B[31" + new String(b, off, len, getCharset()) + "\u001b[0m");
                }
            }
        };
    }

    @Override
    public void open() throws Exception {
        try {
            this.channel = session.getClientSession().createShellChannel();
            // 设置终端类型
            this.channel.setupSensibleDefaultPty();
            this.channel.setPtyType("xterm");
            this.channel.setEnv("TERM", "xterm");
            this.channel.setEnv("LANG", "en_US.UTF-8");
            this.channel.setOut(outputStream);
            this.channel.setErr(errStream);
            this.channel.open().verify(CoreModuleProperties.CHANNEL_OPEN_TIMEOUT.getRequiredDefault());
        } catch (SshException e) {
            if (e.getCause() instanceof TimeoutException) {
                throw new SSHException("会话连接超时");
            } if (e.getCause() instanceof SshChannelOpenException) {
                session.getClientSession().close();
                throw new SSHException("会话连接异常，请重试");
            } else {
                throw e;
            }
        }
    }

    public void changePtySize(int cols, int rows) throws IOException {
        this.channel.sendWindowChange(cols, rows);
    }

    public void changeCharset(String charset) throws IOException {
        this.charset = Charset.forName(charset);
    }

    private Charset getCharset() {
        return this.charset;
    }

    public void setOut(Consumer<String> out) {
        this.out = out;
    }

    public OutputStream getInvertedIn() {
        return this.channel.getInvertedIn();
    }

    private Consumer<String> getOut() {
        return out;
    }

    public void send(String cmd) throws IOException {
        OutputStream out = this.channel.getInvertedIn();
        out.write((cmd + "\n").getBytes());
        out.flush();
    }

    public void execute() throws IOException, InterruptedException {


        // 打开通道
//            channel.setStreaming(ChannelShell.Streaming.Async);
        channel.open().verify(CoreModuleProperties.CHANNEL_OPEN_TIMEOUT.getRequiredDefault());

        // 获取通道的输入输出流
        OutputStream out = channel.getInvertedIn(); // 从客户端发送到服务器
        InputStream in = channel.getInvertedOut(); // 从服务器发送到客户端
        channel.sendWindowChange(80, 100, 80, 24); // 设置初始窗口大小

        // 启动一个线程来读取远程shell的输出并打印到标准输出
        // 确保实时输出
        Thread outputThread = new Thread(() -> {
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) {
                char[] buffer = new char[1024];
                int len;
                while ((len = reader.read(buffer)) != -1) {
                    String s = new String(buffer, 0, len);
                    System.out.print(s);
                    System.out.flush(); // 确保实时输出
                }
            } catch (Exception e) {
                System.err.println("Error reading server output: " + e.getMessage());
            }
        });
        outputThread.setName(session.getUsername().concat("_ShellThread"));
        outputThread.start();

        // 主线程读取用户输入并写入到远程shell
            /*try (BufferedReader localReader = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8))) {
                String command;
                while ((command = localReader.readLine()) != null) {
                    if ("exit".equals(command.trim())) break;
                    out.write((command + "\n").getBytes(StandardCharsets.UTF_8));
                    out.flush();

                    out.write(("\n").getBytes(StandardCharsets.UTF_8));
                    out.flush();

                    // 等待直到看到提示符或超时
//                    synchronized (outputThread) {
//                        try {
//                            outputThread.wait(10 * 1000L);
//                            System.out.println("Command execution timed out after 3 seconds");
////                                logger.warn("Command execution timed out after {} seconds", COMMAND_TIMEOUT);
//                                // 尝试发送中断信号
//                            out.write("\u0003".getBytes(StandardCharsets.UTF_8)); // Ctrl+C
//                            out.flush();
//
//                        } catch (InterruptedException e) {
////                            logger.warn("Output thread was interrupted", e);
//                            Thread.currentThread().interrupt(); // Restore interrupted status
//                        }
//                    }
                }
            }*/

        Thread inputThread = new Thread(() -> {
            try (BufferedReader userInputReader = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8))) {
                String line;
                while ((line = userInputReader.readLine()) != null) {
                    if ("exit1".equalsIgnoreCase(line.trim())) {
                        channel.close(false);
                        break;
                    }
                    out.write((line + "\n").getBytes());
                    out.flush();
                }
            } catch (Exception e) {
                System.err.println("Error handling user input: " + e.getMessage());
            }
        });
        inputThread.setName(session.getUsername().concat("_ShellThread8"));
        inputThread.start();

        // 等待通道关闭
//            Set<ClientChannelEvent> events = channel.waitFor(Collections.singleton(ClientChannelEvent.CLOSED), 0);
//            if (events.contains(ClientChannelEvent.TIMEOUT)){
//                channel.close(false);
//            }
//            System.out.println(channel.isClosed());
//            while (channel.isClosed()) {
//                System.out.println("closing");
//                Thread.sleep(500);
//            }
        System.out.println("closed");
            /*// 发送退出命令并等待通道关闭
            out.write(("exit\n").getBytes(StandardCharsets.UTF_8));
            out.flush();
            // 等待通道关闭
            Set<ClientChannelEvent> events = channel.waitFor(Collections.singleton(ClientChannelEvent.CLOSED), 1000);
            if (events.contains(ClientChannelEvent.TIMEOUT)){
                channel.close(false);
            }
            Thread.sleep(1000);
            System.out.println(channel.isClosed());*/
    }

    @Override
    public void close() throws IOException {
        this.channel.close(false);
    }
}
